home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1843 / 1843.xpi / content / firebug / console.js < prev    next >
Text File  |  2010-01-15  |  29KB  |  936 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7.  
  8. const Cc = Components.classes;
  9. const Ci = Components.interfaces;
  10. const nsIPrefBranch2 = Ci.nsIPrefBranch2;
  11. const PrefService = Cc["@mozilla.org/preferences-service;1"];
  12. const prefs = PrefService.getService(nsIPrefBranch2);
  13.  
  14. // ************************************************************************************************
  15.  
  16. var maxQueueRequests = 500;
  17.  
  18. // ************************************************************************************************
  19.  
  20. Firebug.ConsoleBase =
  21. {
  22.     log: function(object, context, className, rep, noThrottle, sourceLink)
  23.     {
  24.         dispatch(this.fbListeners,"log",[context, object, className, sourceLink]);
  25.         return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle);
  26.     },
  27.  
  28.     logFormatted: function(objects, context, className, noThrottle, sourceLink)
  29.     {
  30.         dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]);
  31.         return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle);
  32.     },
  33.  
  34.     openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush)
  35.     {
  36.         return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle);
  37.     },
  38.  
  39.     closeGroup: function(context, noThrottle)
  40.     {
  41.         return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true);
  42.     },
  43.  
  44.     logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
  45.     {
  46.         if (!context)
  47.             context = FirebugContext;
  48.  
  49.         if (!context)
  50.             return;
  51.  
  52.         if (noThrottle || !context)
  53.         {
  54.             var panel = this.getPanel(context);
  55.             if (panel)
  56.             {
  57.                 var row = panel.append(appender, objects, className, rep, sourceLink, noRow);
  58.                 var container = panel.panelNode;
  59.                 var template = Firebug.NetMonitor.NetLimit;
  60.  
  61.                 while (container.childNodes.length > maxQueueRequests + 1)
  62.                 {
  63.                     clearDomplate(container.firstChild.nextSibling);
  64.                     container.removeChild(container.firstChild.nextSibling);
  65.                     panel.limit.limitInfo.totalCount++;
  66.                     template.updateCounter(panel.limit);
  67.                 }
  68.                 dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]);
  69.                 return row;
  70.             }
  71.         }
  72.         else
  73.         {
  74.             if (!context.throttle)
  75.             {
  76.                 FBTrace.sysout("console.logRow has not context.throttle! ");
  77.                 return;
  78.             }
  79.             var args = [appender, objects, context, className, rep, sourceLink, true, noRow];
  80.             context.throttle(this.logRow, this, args);
  81.         }
  82.     },
  83.  
  84.     appendFormatted: function(args, row, context)
  85.     {
  86.         if (!context)
  87.             context = FirebugContext;
  88.  
  89.         var panel = this.getPanel(context);
  90.         panel.appendFormatted(args, row);
  91.     },
  92.  
  93.     clear: function(context)
  94.     {
  95.         if (!context)
  96.             context = FirebugContext;
  97.  
  98.         if (context)
  99.             Firebug.Errors.clear(context);
  100.  
  101.         var panel = this.getPanel(context, true);
  102.         if (panel)
  103.             panel.clear();
  104.     },
  105.  
  106.     // Override to direct output to your panel
  107.     getPanel: function(context, noCreate)
  108.     {
  109.         if (context)
  110.             return context.getPanel("console", noCreate);
  111.     },
  112.  
  113. };
  114.  
  115. // ************************************************************************************************
  116.  
  117. var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase);
  118.  
  119. Firebug.Console = extend(ActivableConsole,
  120. {
  121.     dispatchName: "console",
  122.  
  123.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  124.     // extends Module
  125.  
  126.     showPanel: function(browser, panel)
  127.     {
  128.     },
  129.  
  130.     getFirebugConsoleElement: function(context, win)
  131.     {
  132.         var element = win.document.getElementById("_firebugConsole");
  133.         if (!element)
  134.         {
  135.             var elementForcer = "(function(){var r=null; try { r = window._getFirebugConsoleElement();}catch(exc){r=exc;} return r;})();";  // we could just add the elements here
  136.  
  137.             if (context.stopped)
  138.                 Firebug.Console.injector.evaluateConsoleScript(context);  // todo evaluate consoleForcer on stack
  139.             else
  140.                 var r = Firebug.CommandLine.evaluateInWebPage(elementForcer, context, win);
  141.  
  142.             var element = win.document.getElementById("_firebugConsole");
  143.             if (!element) // elementForce fails
  144.             {
  145.                 Firebug.Console.logFormatted(["Firebug cannot find _firebugConsole element", r, win], context, "error", true);
  146.             }
  147.         }
  148.  
  149.         return element;
  150.     },
  151.  
  152.     isReadyElsePreparing: function(context, win) // this is the only code that should call injector.attachIfNeeded
  153.     {
  154.         if (win)
  155.             return this.injector.attachIfNeeded(context, win);
  156.         else
  157.         {
  158.             var attached = true;
  159.             for (var i = 0; i < context.windows.length; i++)
  160.                 attached = attached && this.injector.attachIfNeeded(context, context.windows[i]);
  161.             // already in the list above attached = attached && this.injector.attachIfNeeded(context, context.window);
  162.             if (context.windows.indexOf(context.window) == -1)
  163.                 FBTrace.sysout("isReadyElsePreparing ***************** context.window not in context.windows");
  164.             return attached;
  165.         }
  166.     },
  167.  
  168.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  169.     // extends ActivableModule
  170.  
  171.     initialize: function()
  172.     {
  173.         this.panelName = "console";
  174.  
  175.         Firebug.ActivableModule.initialize.apply(this, arguments);
  176.         Firebug.Debugger.addListener(this);
  177.  
  178.     },
  179.  
  180.     enable: function()
  181.     {
  182.         if (Firebug.Console.isAlwaysEnabled())
  183.             this.watchForErrors();
  184.     },
  185.  
  186.     disable: function()
  187.     {
  188.         if (Firebug.Console.isAlwaysEnabled())
  189.             this.unwatchForErrors();
  190.     },
  191.  
  192.     initContext: function(context, persistedState)
  193.     {
  194.         Firebug.ActivableModule.initContext.apply(this, arguments);
  195.         context.consoleReloadWarning = true;  // mark as need to warn.
  196.     },
  197.  
  198.     loadedContext: function(context)
  199.     {
  200.         for (var url in context.sourceFileMap)
  201.             return;  // if there are any sourceFiles, then do nothing
  202.  
  203.         // else we saw no JS, so the reload warning it not needed.
  204.         this.clearReloadWarning(context);
  205.     },
  206.  
  207.     clearReloadWarning: function(context) // remove the warning about reloading.
  208.     {
  209.          if (context.consoleReloadWarning)
  210.          {
  211.              var panel = context.getPanel(this.panelName);
  212.              panel.clearReloadWarning();
  213.              delete context.consoleReloadWarning;
  214.          }
  215.     },
  216.  
  217.     togglePersist: function(context)
  218.     {
  219.         var panel = context.getPanel(this.panelName);
  220.         panel.persistContent = panel.persistContent ? false : true;
  221.         Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", panel.persistContent);
  222.     },
  223.  
  224.     showContext: function(browser, context)
  225.     {
  226.         Firebug.chrome.setGlobalAttribute("cmd_clearConsole", "disabled", !context);
  227.  
  228.         Firebug.ActivableModule.showContext.apply(this, arguments);
  229.     },
  230.  
  231.     destroyContext: function(context, persistedState)
  232.     {
  233.         Firebug.Console.injector.detachConsole(context, context.window);  // TODO iterate windows?
  234.     },
  235.  
  236.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  237.  
  238.     onPanelEnable: function(panelName)
  239.     {
  240.         if (panelName != this.panelName)  // we don't care about other panels
  241.             return;
  242.  
  243.         this.watchForErrors();
  244.         Firebug.Debugger.addDependentModule(this); // we inject the console during JS compiles so we need jsd
  245.     },
  246.  
  247.     onPanelDisable: function(panelName)
  248.     {
  249.         if (panelName != this.panelName)  // we don't care about other panels
  250.             return;
  251.  
  252.         Firebug.Debugger.removeDependentModule(this); // we inject the console during JS compiles so we need jsd
  253.         this.unwatchForErrors();
  254.  
  255.         // Make sure possible errors coming from the page and displayed in the Firefox
  256.         // status bar are removed.
  257.         this.clear();
  258.     },
  259.  
  260.     onSuspendFirebug: function()
  261.     {
  262.         if (Firebug.Console.isAlwaysEnabled())
  263.             this.unwatchForErrors();
  264.     },
  265.  
  266.     onResumeFirebug: function()
  267.     {
  268.         if (Firebug.Console.isAlwaysEnabled())
  269.             this.watchForErrors();
  270.     },
  271.  
  272.     watchForErrors: function()
  273.     {
  274.         Firebug.Errors.checkEnabled();
  275.         $('fbStatusIcon').setAttribute("console", "on");
  276.     },
  277.  
  278.     unwatchForErrors: function()
  279.     {
  280.         Firebug.Errors.checkEnabled();
  281.         $('fbStatusIcon').removeAttribute("console");
  282.     },
  283.  
  284.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  285.     // Firebug.Debugger listener
  286.  
  287.     onMonitorScript: function(context, frame)
  288.     {
  289.         Firebug.Console.log(frame, context);
  290.     },
  291.  
  292.     onFunctionCall: function(context, frame, depth, calling)
  293.     {
  294.         if (calling)
  295.             Firebug.Console.openGroup([frame, "depth:"+depth], context);
  296.         else
  297.             Firebug.Console.closeGroup(context);
  298.     },
  299.  
  300.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  301.  
  302.     logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
  303.     {
  304.         if (!context)
  305.             context = FirebugContext;
  306.  
  307.         if (this.isAlwaysEnabled())
  308.             return Firebug.ConsoleBase.logRow.apply(this, arguments);
  309.     },
  310. });
  311.  
  312. Firebug.ConsoleListener =
  313. {
  314.     log: function(context, object, className, sourceLink)
  315.     {
  316.     },
  317.  
  318.     logFormatted: function(context, objects, className, sourceLink)
  319.     {
  320.     }
  321. };
  322.  
  323. // ************************************************************************************************
  324.  
  325. Firebug.ConsolePanel = function () {} // XXjjb attach Firebug so this panel can be extended.
  326.  
  327. Firebug.ConsolePanel.prototype = extend(Firebug.ActivablePanel,
  328. {
  329.     wasScrolledToBottom: false,
  330.     messageCount: 0,
  331.     lastLogTime: 0,
  332.     groups: null,
  333.     limit: null,
  334.  
  335.     append: function(appender, objects, className, rep, sourceLink, noRow)
  336.     {
  337.         var container = this.getTopContainer();
  338.  
  339.         if (noRow)
  340.         {
  341.             appender.apply(this, [objects]);
  342.         }
  343.         else
  344.         {
  345.             // Don't update the this.wasScrolledToBottom flag now. At the beginning (when the
  346.             // first log is created) the isScrolledToBottom always returns true.
  347.             // But make sure the panel scrolls if it should.
  348.             var wasScrolledToBottom = false;
  349.             if (this.panelNode.offsetHeight)
  350.                 wasScrolledToBottom = isScrolledToBottom(this.panelNode);
  351.  
  352.             var row = this.createRow("logRow", className);
  353.             appender.apply(this, [objects, row, rep]);
  354.  
  355.             if (sourceLink)
  356.                 FirebugReps.SourceLink.tag.append({object: sourceLink}, row);
  357.  
  358.             container.appendChild(row);
  359.  
  360.             this.filterLogRow(row, this.wasScrolledToBottom);
  361.  
  362.             if (wasScrolledToBottom)
  363.                 scrollToBottom(this.panelNode);
  364.  
  365.             return row;
  366.         }
  367.     },
  368.  
  369.     clear: function()
  370.     {
  371.         if (this.panelNode)
  372.         {
  373.             clearNode(this.panelNode);
  374.             this.insertLogLimit(this.context);
  375.         }
  376.     },
  377.  
  378.     insertLogLimit: function()
  379.     {
  380.         // Create limit row. This row is the first in the list of entries
  381.         // and initially hidden. It's displayed as soon as the number of
  382.         // entries reaches the limit.
  383.         var row = this.createRow("limitRow");
  384.  
  385.         var limitInfo = {
  386.             totalCount: 0,
  387.             limitPrefsTitle: $STRF("LimitPrefsTitle", [Firebug.prefDomain+".console.logLimit"])
  388.         };
  389.  
  390.         var netLimitRep = Firebug.NetMonitor.NetLimit;
  391.         var nodes = netLimitRep.createTable(row, limitInfo);
  392.  
  393.         this.limit = nodes[1];
  394.  
  395.         var container = this.panelNode;
  396.         container.insertBefore(nodes[0], container.firstChild);
  397.     },
  398.  
  399.     insertReloadWarning: function()
  400.     {
  401.         // put the message in, we will clear if the window console is injected.
  402.         this.warningRow = this.append(appendObject, $STR("message.Reload to activate window console"), "info");
  403.     },
  404.  
  405.     clearReloadWarning: function()
  406.     {
  407.         if (this.warningRow)
  408.         {
  409.             this.warningRow.parentNode.removeChild(this.warningRow);
  410.             delete this.warningRow;
  411.         }
  412.     },
  413.  
  414.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  415.  
  416.     appendObject: function(object, row, rep)
  417.     {
  418.         if (!rep)
  419.             rep = Firebug.getRep(object);
  420.         return rep.tag.append({object: object}, row);
  421.     },
  422.  
  423.     appendFormatted: function(objects, row, rep)
  424.     {
  425.         if (!objects || !objects.length)
  426.             return;
  427.  
  428.         function logText(text, row)
  429.         {
  430.             var node = row.ownerDocument.createTextNode(text);
  431.             row.appendChild(node);
  432.         }
  433.  
  434.         var format = objects[0];
  435.         var objIndex = 0;
  436.  
  437.         if (typeof(format) != "string")
  438.         {
  439.             format = "";
  440.             objIndex = -1;
  441.         }
  442.         else  // a string
  443.         {
  444.             if (objects.length === 1) // then we have only a string...
  445.             {
  446.                 if (format.length < 1) { // ...and it has no characters.
  447.                     logText("(an empty string)", row);
  448.                     return;
  449.                 }
  450.             }
  451.         }
  452.  
  453.         var parts = parseFormat(format);
  454.         var trialIndex = objIndex;
  455.         for (var i= 0; i < parts.length; i++)
  456.         {
  457.             var part = parts[i];
  458.             if (part && typeof(part) == "object")
  459.             {
  460.                 if (++trialIndex > objects.length)  // then too few parameters for format, assume unformatted.
  461.                 {
  462.                     format = "";
  463.                     objIndex = -1;
  464.                     parts.length = 0;
  465.                     break;
  466.                 }
  467.             }
  468.  
  469.         }
  470.         for (var i = 0; i < parts.length; ++i)
  471.         {
  472.             var part = parts[i];
  473.             if (part && typeof(part) == "object")
  474.             {
  475.                 var object = objects[++objIndex];
  476.                 if (part.type == "%c")
  477.                     row.setAttribute("style", object.toString());
  478.                 else if (typeof(object) != "undefined")
  479.                     this.appendObject(object, row, part.rep);
  480.                 else
  481.                     this.appendObject(part.type, row, FirebugReps.Text);
  482.             }
  483.             else
  484.                 FirebugReps.Text.tag.append({object: part}, row);
  485.         }
  486.  
  487.         for (var i = objIndex+1; i < objects.length; ++i)
  488.         {
  489.             logText(" ", row);
  490.             var object = objects[i];
  491.             if (typeof(object) == "string")
  492.                 FirebugReps.Text.tag.append({object: object}, row);
  493.             else
  494.                 this.appendObject(object, row);
  495.         }
  496.     },
  497.  
  498.     appendOpenGroup: function(objects, row, rep)
  499.     {
  500.         if (!this.groups)
  501.             this.groups = [];
  502.  
  503.         setClass(row, "logGroup");
  504.         setClass(row, "opened");
  505.  
  506.         var innerRow = this.createRow("logRow");
  507.         setClass(innerRow, "logGroupLabel");
  508.         if (rep)
  509.             rep.tag.replace({"objects": objects}, innerRow);
  510.         else
  511.             this.appendFormatted(objects, innerRow, rep);
  512.         row.appendChild(innerRow);
  513.         dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]);
  514.         var groupBody = this.createRow("logGroupBody");
  515.         row.appendChild(groupBody);
  516.         groupBody.setAttribute('role', 'group');
  517.         this.groups.push(groupBody);
  518.  
  519.         innerRow.addEventListener("mousedown", function(event)
  520.         {
  521.             if (isLeftClick(event))
  522.             {
  523.                 var groupRow = event.currentTarget.parentNode;
  524.                 if (hasClass(groupRow, "opened"))
  525.                 {
  526.                     removeClass(groupRow, "opened");
  527.                     event.target.setAttribute('aria-expanded', 'false');
  528.                 }
  529.                 else
  530.                 {
  531.                     setClass(groupRow, "opened");
  532.                     event.target.setAttribute('aria-expanded', 'true');
  533.                 }
  534.             }
  535.         }, false);
  536.     },
  537.  
  538.     appendCloseGroup: function(object, row, rep)
  539.     {
  540.         if (this.groups)
  541.             this.groups.pop();
  542.     },
  543.  
  544.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  545.     // extends Panel
  546.  
  547.     name: "console",
  548.     searchable: true,
  549.     breakable: true,
  550.     editable: false,
  551.  
  552.     initialize: function()
  553.     {
  554.         Firebug.ActivablePanel.initialize.apply(this, arguments);  // loads persisted content
  555.  
  556.         if (!this.persistedContent && Firebug.Console.isAlwaysEnabled())
  557.         {
  558.             this.insertLogLimit(this.context);
  559.  
  560.             // Initialize log limit and listen for changes.
  561.             this.updateMaxLimit();
  562.  
  563.             if (this.context.consoleReloadWarning)  // we have not yet injected the console
  564.                 this.insertReloadWarning();
  565.         }
  566.  
  567.         prefs.addObserver(Firebug.prefDomain, this, false);
  568.     },
  569.  
  570.     initializeNode : function()
  571.     {
  572.         dispatch([Firebug.A11yModel], 'onInitializeNode', [this]);
  573.         this.onResizer = bind(this.onResize, this);
  574.         this.resizeEventTarget = Firebug.chrome.$('fbContentBox');
  575.         this.resizeEventTarget.addEventListener("resize", this.onResizer, true);
  576.     },
  577.  
  578.     destroyNode : function()
  579.     {
  580.         dispatch([Firebug.A11yModel], 'onDestroyNode', [this]);
  581.         if (this.onScroller)
  582.             this.panelNode.removeEventListener("scroll", this.onScroller, true);
  583.  
  584.         this.resizeEventTarget.removeEventListener("resize", this.onResizer, true);
  585.     },
  586.  
  587.     shutdown: function()
  588.     {
  589.         prefs.removeObserver(Firebug.prefDomain, this, false);
  590.     },
  591.  
  592.     show: function(state)
  593.     {
  594.         var enabled = Firebug.Console.isAlwaysEnabled();
  595.         if (enabled)
  596.         {
  597.              Firebug.Console.disabledPanelPage.hide(this);
  598.              this.showCommandLine(true);
  599.              this.showToolbarButtons("fbConsoleButtons", true);
  600.              Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent);
  601.  
  602.              if (state && state.wasScrolledToBottom)
  603.              {
  604.                  this.wasScrolledToBottom = state.wasScrolledToBottom;
  605.                  delete state.wasScrolledToBottom;
  606.              }
  607.  
  608.              if (this.wasScrolledToBottom)
  609.                  scrollToBottom(this.panelNode);
  610.  
  611.              if (state && state.profileRow) // then we reloaded while profiling
  612.              {
  613.                  FBTrace.sysout("console.initialize state.profileRow:", state.profileRow);
  614.                  this.context.profileRow = state.profileRow;
  615.                  this.panelNode.appendChild(state.profileRow);
  616.                  delete state.profileRow;
  617.              }
  618.         }
  619.         else
  620.         {
  621.             this.hide(state);
  622.             Firebug.Console.disabledPanelPage.show(this);
  623.         }
  624.     },
  625.  
  626.     hide: function(state)
  627.     {
  628.         this.showToolbarButtons("fbConsoleButtons", false);
  629.         this.showCommandLine(false);
  630.  
  631.     },
  632.  
  633.     destroy: function(state)
  634.     {
  635.         Firebug.ActivablePanel.destroy.apply(this, arguments);
  636.  
  637.         if (this.panelNode.offsetHeight)
  638.             this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
  639.  
  640.         if (state)
  641.             state.wasScrolledToBottom = this.wasScrolledToBottom;
  642.  
  643.         // If we are profiling and reloading, save the profileRow for the new context
  644.         if (this.context.profileRow && this.context.profileRow.ownerDocument)
  645.         {
  646.             this.context.profileRow.parentNode.removeChild(this.context.profileRow);
  647.             state.profileRow = this.context.profileRow;
  648.         }
  649.  
  650.     },
  651.  
  652.     shouldBreakOnNext: function()
  653.     {
  654.         // xxxHonza: shouldn't the breakOnErrors be context related?
  655.         // xxxJJB, yes, but we can't support it because we can't yet tell
  656.         // which window the error is on.
  657.         return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors");
  658.     },
  659.  
  660.     getBreakOnNextTooltip: function(enabled)
  661.     {
  662.         return (enabled ? $STR("console.Disable Break On All Errors") :
  663.             $STR("console.Break On All Errors"));
  664.     },
  665.  
  666.     enablePanel: function(module)
  667.     {
  668.         Firebug.ActivablePanel.enablePanel.apply(this, arguments);
  669.  
  670.         this.showCommandLine(true);
  671.  
  672.         if (this.wasScrolledToBottom)
  673.             scrollToBottom(this.panelNode);
  674.     },
  675.  
  676.     disablePanel: function(module)
  677.     {
  678.         Firebug.ActivablePanel.disablePanel.apply(this, arguments);
  679.  
  680.         this.showCommandLine(false);
  681.     },
  682.  
  683.     getOptionsMenuItems: function()
  684.     {
  685.         return [
  686.             optionMenu("ShowJavaScriptErrors", "showJSErrors"),
  687.             optionMenu("ShowJavaScriptWarnings", "showJSWarnings"),
  688.             optionMenu("ShowCSSErrors", "showCSSErrors"),
  689.             optionMenu("ShowXMLErrors", "showXMLErrors"),
  690.             optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"),
  691.             optionMenu("ShowChromeErrors", "showChromeErrors"),
  692.             optionMenu("ShowChromeMessages", "showChromeMessages"),
  693.             optionMenu("ShowExternalErrors", "showExternalErrors"),
  694.             optionMenu("ShowNetworkErrors", "showNetworkErrors"),
  695.             this.getShowStackTraceMenuItem(),
  696.             this.getStrictOptionMenuItem(),
  697.             "-",
  698.             optionMenu("LargeCommandLine", "largeCommandLine")
  699.         ];
  700.     },
  701.  
  702.     getShowStackTraceMenuItem: function()
  703.     {
  704.         var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace");
  705.         if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled())
  706.             menuItem.disabled = true;
  707.         return menuItem;
  708.     },
  709.  
  710.     getStrictOptionMenuItem: function()
  711.     {
  712.         var strictDomain = "javascript.options";
  713.         var strictName = "strict";
  714.         var strictValue = prefs.getBoolPref(strictDomain+"."+strictName);
  715.         return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue,
  716.             command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) };
  717.     },
  718.  
  719.     getBreakOnMenuItems: function()
  720.     {
  721.         //xxxHonza: no BON options for now.
  722.         /*return [
  723.             optionMenu("console.option.Persist Break On Error", "persistBreakOnError")
  724.         ];*/
  725.        return [];
  726.     },
  727.  
  728.     search: function(text)
  729.     {
  730.         if (!text)
  731.             return;
  732.  
  733.         // Make previously visible nodes invisible again
  734.         if (this.matchSet)
  735.         {
  736.             for (var i in this.matchSet)
  737.                 removeClass(this.matchSet[i], "matched");
  738.         }
  739.  
  740.         this.matchSet = [];
  741.  
  742.         function findRow(node) { return getAncestorByClass(node, "logRow"); }
  743.         var search = new TextSearch(this.panelNode, findRow);
  744.  
  745.         var logRow = search.find(text);
  746.         if (!logRow)
  747.         {
  748.             dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]);
  749.             return false;
  750.         }
  751.         for (; logRow; logRow = search.findNext())
  752.         {
  753.             setClass(logRow, "matched");
  754.             this.matchSet.push(logRow);
  755.         }
  756.         dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]);
  757.         return true;
  758.     },
  759.  
  760.     breakOnNext: function(breaking)
  761.     {
  762.         Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking);
  763.     },
  764.  
  765.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  766.     // private
  767.  
  768.     createRow: function(rowName, className)
  769.     {
  770.         var elt = this.document.createElement("div");
  771.         elt.className = rowName + (className ? " " + rowName + "-" + className : "");
  772.         return elt;
  773.     },
  774.  
  775.     getTopContainer: function()
  776.     {
  777.         if (this.groups && this.groups.length)
  778.             return this.groups[this.groups.length-1];
  779.         else
  780.             return this.panelNode;
  781.     },
  782.  
  783.     filterLogRow: function(logRow, scrolledToBottom)
  784.     {
  785.         if (this.searchText)
  786.         {
  787.             setClass(logRow, "matching");
  788.             setClass(logRow, "matched");
  789.  
  790.             // Search after a delay because we must wait for a frame to be created for
  791.             // the new logRow so that the finder will be able to locate it
  792.             setTimeout(bindFixed(function()
  793.             {
  794.                 if (this.searchFilter(this.searchText, logRow))
  795.                     this.matchSet.push(logRow);
  796.                 else
  797.                     removeClass(logRow, "matched");
  798.  
  799.                 removeClass(logRow, "matching");
  800.  
  801.                 if (scrolledToBottom)
  802.                     scrollToBottom(this.panelNode);
  803.             }, this), 100);
  804.         }
  805.     },
  806.  
  807.     searchFilter: function(text, logRow)
  808.     {
  809.         var count = this.panelNode.childNodes.length;
  810.         var searchRange = this.document.createRange();
  811.         searchRange.setStart(this.panelNode, 0);
  812.         searchRange.setEnd(this.panelNode, count);
  813.  
  814.         var startPt = this.document.createRange();
  815.         startPt.setStartBefore(logRow);
  816.  
  817.         var endPt = this.document.createRange();
  818.         endPt.setStartAfter(logRow);
  819.  
  820.         return finder.Find(text, searchRange, startPt, endPt) != null;
  821.     },
  822.  
  823.     // nsIPrefObserver
  824.     observe: function(subject, topic, data)
  825.     {
  826.         // We're observing preferences only.
  827.         if (topic != "nsPref:changed")
  828.           return;
  829.  
  830.         // xxxHonza check this out.
  831.         var prefDomain = "Firebug.extension.";
  832.         var prefName = data.substr(prefDomain.length);
  833.         if (prefName == "console.logLimit")
  834.             this.updateMaxLimit();
  835.     },
  836.  
  837.     updateMaxLimit: function()
  838.     {
  839.         var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit");
  840.         maxQueueRequests =  value ? value : maxQueueRequests;
  841.     },
  842.  
  843.     showCommandLine: function(shouldShow)
  844.     {
  845.         if (shouldShow)
  846.         {
  847.             collapse(Firebug.chrome.$("fbCommandBox"), false);
  848.             Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome);
  849.         }
  850.         else
  851.         {
  852.             // Make sure that entire content of the Console panel is hidden when
  853.             // the panel is disabled.
  854.             Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine);
  855.             collapse(Firebug.chrome.$("fbCommandBox"), true);
  856.         }
  857.     },
  858.  
  859.     onScroll: function(event)
  860.     {
  861.         // Update the scroll position flag if the position changes.
  862.         this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode);
  863.  
  864.     },
  865.  
  866.     onResize: function(event)
  867.     {
  868.         if (this.wasScrolledToBottom)
  869.             scrollToBottom(this.panelNode);
  870.     },
  871. });
  872.  
  873. // ************************************************************************************************
  874.  
  875. function parseFormat(format)
  876. {
  877.     var parts = [];
  878.     if (format.length <= 0)
  879.         return parts;
  880.  
  881.     var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/;
  882.     for (var m = reg.exec(format); m; m = reg.exec(format))
  883.     {
  884.         if (m[0].substr(0, 2) == "%%")
  885.         {
  886.             parts.push(format.substr(0, m.index));
  887.             parts.push(m[0].substr(1));
  888.         }
  889.         else
  890.         {
  891.             var type = m[8] ? m[8] : m[5];
  892.             var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
  893.  
  894.             var rep = null;
  895.             switch (type)
  896.             {
  897.                 case "s":
  898.                     rep = FirebugReps.Text;
  899.                     break;
  900.                 case "f":
  901.                 case "i":
  902.                 case "d":
  903.                     rep = FirebugReps.Number;
  904.                     break;
  905.                 case "o":
  906.                 case "c":
  907.                     rep = null;
  908.                     break;
  909.             }
  910.  
  911.             parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
  912.             parts.push({rep: rep, precision: precision, type: ("%" + type)});
  913.         }
  914.  
  915.         format = format.substr(m.index+m[0].length);
  916.     }
  917.  
  918.     parts.push(format);
  919.     return parts;
  920. }
  921.  
  922. // ************************************************************************************************
  923.  
  924. var appendObject = Firebug.ConsolePanel.prototype.appendObject;
  925. var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted;
  926. var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup;
  927. var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup;
  928.  
  929. // ************************************************************************************************
  930.  
  931. Firebug.registerActivableModule(Firebug.Console);
  932. Firebug.registerPanel(Firebug.ConsolePanel);
  933.  
  934. // ************************************************************************************************
  935. }});
  936.